package glossos.tree.snapshot;

import glossos.tree.Node;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class JdbcNodeRepository extends SimpleJdbcDaoSupport implements NodeRepository{
	private static Logger logger = Logger.getLogger(JdbcNodeRepository.class);
	private static final String findByIdSql = "select * from node where id = ?";
	private static final String findByParentIdSql = "select * from node where parent_id = ?";
	private static final String findByParentIdAndWordSql = "select * from node where parent_id = ? and word = ?";
	private static final String insertNodeSql = "insert into node(id, word, frequency, parent_id) values(?, ?, ?, ?)";
	private static final String updateFrequencySql = "update node set frequency = ? where id = ?";
    private static final String maxIdSql = "select max(id) from node";
    private static final String countSql = "select count(1) from node";
    private static final String deleteAllSql = "delete from node";

    private Long nextId;

    public JdbcNodeRepository(){
        logger.debug(this.getClass() + " successfully created.");
    }

    public void save(Node node) {
		if (nodeHasAlreadyBeenInserted(node))
			update(node);
		else
			insert(node);
	}
	
	private void update(Node node){
		getSimpleJdbcTemplate().update(updateFrequencySql, node.getFrequency(), node.getId());
	}

    private void insert(Node node){
        getSimpleJdbcTemplate().update(insertNodeSql, 
        							node.getId(), 
        							node.getWord(), 
        							node.getFrequency(), 
        							node.getParentId());
    }

	private boolean nodeHasAlreadyBeenInserted(Node node)	throws DataAccessException {
        return node.getFrequency() > 1;
    }

	public Node findById(Long id) {
		try {
			return getSimpleJdbcTemplate().queryForObject(findByIdSql, new NodeMapper(this), id);
		} catch (EmptyResultDataAccessException e){
			return null;
		}
	}

	public Set<Node> findByParentId(Long parentId) {
		List<Node> nodes =  getSimpleJdbcTemplate().query(findByParentIdSql, new NodeMapper(this), parentId);
		return new HashSet<Node>(nodes);
	}

	public Node findByParentIdAndWord(Long parentId, String word) {
		try {
			return getSimpleJdbcTemplate().queryForObject(findByParentIdAndWordSql, new NodeMapper(this), parentId, word);
		} catch (EmptyResultDataAccessException e){
			return null;
		}
	}

	public Long nextId() {
        if (nextId == null)
            nextId = getSimpleJdbcTemplate().queryForLong(maxIdSql);
        return ++nextId;
    }

    public Long count() {
        return getSimpleJdbcTemplate().queryForLong(countSql);
    }

    public void removeAll() {
        getSimpleJdbcTemplate().update(deleteAllSql);
    }
}
